package com.neusoft.neuiotms.dcom.service.impl;

import java.util.List;

import javax.persistence.EntityNotFoundException;

import org.apache.commons.lang3.StringUtils;
import org.quartz.CronExpression;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.neusoft.bizcore.auth.common.bean.UserBean;
import com.neusoft.bizcore.schedule.service.JobMgrService;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.neuiotms.dcom.converter.InspectionRuleConverter;
import com.neusoft.neuiotms.dcom.dto.InspectionRuleDTO;
import com.neusoft.neuiotms.dcom.model.InspectionRule;
import com.neusoft.neuiotms.dcom.model.enums.InspectionRuleStatus;
import com.neusoft.neuiotms.dcom.repository.InspectionRuleRepository;
import com.neusoft.neuiotms.dcom.service.InspectionRuleService;
import com.neusoft.neuiotms.dcom.task.InspectionTaskJob;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class InspectionRuleServiceImpl implements InspectionRuleService {

    @Autowired
    private InspectionRuleRepository ruleRepository;

    @Autowired
    private InspectionRuleConverter ruleConverter;

    @Autowired
    private JobMgrService jobMgrService;

    @Override
    public List<InspectionRuleDTO> index(final Searchable searchable, final UserBean user) {
        if (user != null) {
            searchable.put("orgCodes", user.getOrgs());
            //            searchable.put("delFlag", 0);
        }
        final List<InspectionRule> models = this.ruleRepository.index(searchable);
        return this.ruleConverter.toListDTO(models);
    }

    @Override
    public Page<InspectionRuleDTO> page(final Searchable searchable, final Pageable pageable, final UserBean user) {
        if (user != null) {
            searchable.put("orgCodes", user.getOrgs());
            searchable.put("delFlag", 0);
        }
        final Page<InspectionRule> models = this.ruleRepository.page(searchable, pageable);
        return this.ruleConverter.toPageDTO(models);
    }

    @Override
    public InspectionRuleDTO create(final InspectionRuleDTO dto, final UserBean user) {
        final InspectionRule model = this.ruleConverter.toModel(dto);
        if (!CronExpression.isValidExpression(dto.getCronTime())) {
            throw new UnitedException("cron表达式不合法", new Object[] {});
        }
        model.setUserCode(StringUtils.isEmpty(user.getUsername()) ? "admin" : user.getUsername());
        model.setUserName(StringUtils.isEmpty(user.getName()) ? "admin" : user.getName());
        model.setVersion(1);
        this.ruleRepository.save(model);
        //设置定时任务
        this.addInspectionScheduleJob(model);
        return this.ruleConverter.toDTO(model);
    }

    @Override
    public InspectionRuleDTO update(final Long id, final InspectionRuleDTO dto, final UserBean user) {
        InspectionRule model;
        try {
            model = this.ruleRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            InspectionRuleServiceImpl.log.error(e.getMessage(), e);
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }
        //已经关联了任务
        if ((model.getInspectionTask() != null) && !model.getInspectionTask().isEmpty()) {
            dto.setId(null);
            dto.getInspectionProject().forEach(p -> {
                p.setId(null);
                p.getProjectConcrete().forEach(c -> {
                    c.setId(null);
                });
                p.getInspectionItem().forEach(i -> {
                    i.setId(null);
                });
            });
            int ver = dto.getVersion().intValue();
            dto.setVersion(++ver);
        }
        //设置更新人的账号信息
        dto.setUserCode(user.getUsername());
        dto.setUserName(user.getName());
        //保存
        model = this.ruleConverter.toModel(dto);
        this.ruleRepository.save(model);
        //设置定时任务
        this.addInspectionScheduleJob(model);
        return this.ruleConverter.toDTO(model);

    }

    @Override
    public InspectionRuleDTO detail(final Long id) {
        try {
            final InspectionRule model = this.ruleRepository.getOne(id);
            return this.ruleConverter.toDTO(model);
        } catch (final EntityNotFoundException e) {
            InspectionRuleServiceImpl.log.error(e.getMessage(), e);
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

    }

    @Override
    public void delete(final Long id) {
        final InspectionRule rule = this.ruleRepository.getOne(id);
        if ((rule.getInspectionTask() != null) && !rule.getInspectionTask().isEmpty()) {
            throw new UnitedException("已经有正在执行的巡检任务，暂不允许删除", new Object[] {id });
        } else {
            //删除之前先删除定时任务
            this.jobMgrService.pauseJob(rule.getCode());
            this.jobMgrService.deleteJob(rule.getCode());

            this.ruleRepository.deleteById(id);
            final List<InspectionRule> list = this.ruleRepository.findByCode(rule.getCode());
            if (!list.isEmpty()) {
                list.forEach(t -> {
                    t.setDelFlag(1);
                });
                this.ruleRepository.saveAll(list);
            }
        }
    }

    @Override
    public void updateStatus(final Long id, final String status) {
        final InspectionRule model = this.ruleRepository.getOne(id);
        model.setStatus(InspectionRuleStatus.valueOf(status));
        this.ruleRepository.save(model);
        //新增定时任务
        if (status.equals(InspectionRuleStatus.start.name())) {
            this.addInspectionScheduleJob(model);
        } else {//删除定时任务
            this.jobMgrService.pauseJob(model.getCode());
            this.jobMgrService.deleteJob(model.getCode());
        }
    }

    private void addInspectionScheduleJob(final InspectionRule model) {
        this.jobMgrService.pauseJob(model.getCode());
        this.jobMgrService.deleteJob(model.getCode());
        if (model.getStatus() == InspectionRuleStatus.start) {
            final JobDetail jobDetail = JobBuilder
                    .newJob((InspectionTaskJob.class))
                    .withIdentity(model.getCode())
                    .withDescription(model.getName())
                    .build();
            jobDetail.getJobDataMap().put("inspectionRuleId", model.getId());
            this.jobMgrService.scheduleCronJob(model.getCode(), model.getCronTime(), jobDetail);
        }
    }
}
